home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 20
/
Aminet 20 (1997)(GTI - Schatztruhe)[!][Aug 1997].iso
/
Aminet
/
comm
/
www
/
HTP.lha
/
HTP
/
source
/
varstore.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-06-21
|
9KB
|
426 lines
/*
//
// varstore.c
//
// Variable store functions (implemented with a simple hash table)
//
// Copyright (c) 1995-96 Jim Nelson. Permission to distribute
// granted by the author. No warranties are made on the fitness of this
// source code.
// Amiga version - 1997 - Geert Bevin
//
*/
#include "htp.h"
/* statistics for performance measurement */
#if DEBUG
uint variableLookups = 0;
uint variableCacheHits = 0;
uint variableStringCompares = 0;
uint variableMissedStringCompares = 0;
uint variableHashCalcs = 0;
#endif
/* !! dont primes contribute to a more evenly distributed hash table? */
/* need to check Knuth ... */
#define HASH_TABLE_SIZE (53)
/*
// generates an index into the hash table from the string
*/
uint StringToHashTableIndex(const char *name)
{
uint hash;
uint ctr;
if(name == NULL)
{
return 0;
}
#if DEBUG
variableHashCalcs++;
#endif
hash = 0;
ctr = 0;
while(*name != NUL)
{
/* uppercase the chars before hashing because names are case-insensitive */
/* shift left to give a broader distribution in the hash table */
hash += (uint) toupper(*name++) << (ctr++ & 0x03);
}
return (hash % HASH_TABLE_SIZE);
}
BOOL InitializeVariableStore(VARSTORE *varstore)
{
assert(varstore != NULL);
/* allocate the hash table */
varstore->variableHashTable = AllocMemory(sizeof(VARIABLE *) * HASH_TABLE_SIZE);
if(varstore->variableHashTable == NULL)
{
DEBUG_PRINT(("out of memory trying to allocate variable hash table"));
return FALSE;
}
memset(varstore->variableHashTable, 0, sizeof(VARIABLE *) * HASH_TABLE_SIZE);
/* initialize the rest of the store */
varstore->parent = NULL;
varstore->child = NULL;
varstore->lastVariable = NULL;
return TRUE;
}
void DestroyVariableStore(VARSTORE *varstore)
{
/* destroy all children as well ... this function doesn't simply "unlink" */
/* the current store from the linked list */
while(varstore != NULL)
{
/* unlink from parent */
if(varstore->parent != NULL)
{
varstore->parent->child = NULL;
varstore->parent = NULL;
}
/* destroy all variables in this store */
ClearVariableList(varstore);
/* free the hash table memory */
FreeMemory(varstore->variableHashTable);
varstore->variableHashTable = NULL;
/* destroy all child scopes as well */
varstore = varstore->child;
}
}
BOOL StoreVariable(VARSTORE *varstore, const char *name, const char *value,
uint type, uint flag, void *param, VAR_DESTRUCTOR destructor)
{
VARIABLE *variable;
VARIABLE *ptr;
uint index;
assert(varstore != NULL);
assert(name != NULL);
/* remove any variable with the same name in the store */
RemoveVariable(varstore, name);
/* allocate space for the variable structure */
if((variable = AllocMemory(sizeof(VARIABLE))) == NULL)
{
DEBUG_PRINT(("unable to allocate memory for new variable"));
return FALSE;
}
/* copy in the variable's name */
StringCopy(variable->name, name, MAX_VARNAME_LEN);
/* copy in the variable's value, if any */
if(value != NULL)
{
StringCopy(variable->value, value, MAX_VARVALUE_LEN);
}
/* set flags and destructor pointer */
variable->type = type;
variable->flag = flag;
variable->param = param;
variable->destructor = destructor;
variable->next = NULL;
/* insert into the hash table */
index = StringToHashTableIndex(name);
ptr = varstore->variableHashTable[index];
varstore->variableHashTable[index] = variable;
if(ptr != NULL)
{
/* the slot has been previously hashed to a different variable, */
/* inserted new item at beginning of list, add rest to end */
variable->next = ptr;
}
/* put this new variable into the last-used cache */
varstore->lastVariable = variable;
return TRUE;
}
static VARIABLE *FindVariable(VARSTORE *varstore, const char *name)
{
VARIABLE *ptr;
assert(varstore != NULL);
assert(name != NULL);
#if DEBUG
variableLookups++;
#endif
/* check the last referenced variable first */
if(varstore->lastVariable != NULL)
{
#if DEBUG
variableStringCompares++;
#endif
if(stricmp(varstore->lastVariable->name, name) == 0)
{
#if DEBUG
variableCacheHits++;
#endif
return varstore->lastVariable;
}
#if DEBUG
variableMissedStringCompares++;
#endif
}
ptr = varstore->variableHashTable[StringToHashTableIndex(name)];
while(ptr != NULL)
{
#if DEBUG
variableStringCompares++;
#endif
if(stricmp(ptr->name, name) == 0)
{
/* cache this variable for next time */
varstore->lastVariable = ptr;
return ptr;
}
#if DEBUG
variableMissedStringCompares++;
#endif
ptr = ptr->next;
}
/* check all parent stores as well */
if(varstore->parent != NULL)
{
return FindVariable(varstore->parent, name);
}
return NULL;
}
const char *GetVariableValue(VARSTORE *varstore, const char *name)
{
VARIABLE *variable;
if(name != NULL)
{
if((variable = FindVariable(varstore, name)) != NULL)
{
return variable->value;
}
}
return NULL;
}
uint GetVariableType(VARSTORE *varstore, const char *name)
{
VARIABLE *variable;
if(name != NULL)
{
if((variable = FindVariable(varstore, name)) != NULL)
{
return variable->type;
}
}
return VAR_TYPE_UNKNOWN;
}
uint GetVariableFlag(VARSTORE *varstore, const char *name)
{
VARIABLE *variable;
if(name != NULL)
{
if((variable = FindVariable(varstore, name)) != NULL)
{
return variable->flag;
}
}
return VAR_FLAG_UNKNOWN;
}
static void DestroyVariable(VARSTORE *varstore, VARIABLE *variable)
{
/* if the variable has a destructor callback, do it */
if(variable->destructor != NULL)
{
variable->destructor(variable->name, variable->value, variable->type,
variable->flag, variable->param);
}
/* if this is the last referenced variable, uncache it */
if(varstore->lastVariable == variable)
{
varstore->lastVariable = NULL;
}
/* free the structure */
FreeMemory(variable);
}
void ClearVariableList(VARSTORE *varstore)
{
VARIABLE *ptr;
VARIABLE *next;
uint ctr;
assert(varstore != NULL);
/* have to walk the entire hash table to destroy each item */
for(ctr = 0; ctr < HASH_TABLE_SIZE; ctr++)
{
ptr = varstore->variableHashTable[ctr];
while(ptr != NULL)
{
next = ptr->next;
DestroyVariable(varstore, ptr);
ptr = next;
}
varstore->variableHashTable[ctr] = NULL;
}
}
BOOL RemoveVariable(VARSTORE *varstore, const char *name)
{
VARIABLE *ptr;
VARIABLE *prev;
uint index;
assert(varstore != NULL);
if(name == NULL)
{
return FALSE;
}
index = StringToHashTableIndex(name);
prev = NULL;
ptr = varstore->variableHashTable[index];
while(ptr != NULL)
{
#if DEBUG
variableStringCompares++;
#endif
if(stricmp(ptr->name, name) == 0)
{
/* found the variable */
/* unlink from the list */
if(prev != NULL)
{
prev->next = ptr->next;
}
else
{
varstore->variableHashTable[index] = ptr->next;
}
/* destroy the variable structure */
DestroyVariable(varstore, ptr);
return TRUE;
}
prev = ptr;
ptr = ptr->next;
}
return FALSE;
}
BOOL VariableExists(VARSTORE *varstore, const char *name)
{
return (FindVariable(varstore, name) != NULL) ? TRUE : FALSE;
}
void *GetVariableParam(VARSTORE *varstore, const char *name)
{
VARIABLE *var;
if(name != NULL)
{
if((var = FindVariable(varstore, name)) != NULL)
{
return var->param;
}
}
return NULL;
}
static VARSTORE *FindTopmostContext(VARSTORE *varstore)
{
VARSTORE *ptr;
assert(varstore != NULL);
ptr = varstore;
while(ptr->child != NULL)
{
assert(ptr->child->parent == ptr);
ptr = ptr->child;
}
return ptr;
}
void PushVariableStoreContext(VARSTORE *parent, VARSTORE *varstore)
{
VARSTORE *ptr;
assert(parent != NULL);
assert(varstore != NULL);
assert(varstore->parent == NULL);
ptr = FindTopmostContext(parent);
ptr->child = varstore;
varstore->parent = ptr;
varstore->child = NULL;
}
VARSTORE *PopVariableStoreContext(VARSTORE *varstore)
{
VARSTORE *ptr;
assert(varstore != NULL);
ptr = FindTopmostContext(varstore);
/* unlink from parent and return current context */
ptr->parent->child = NULL;
ptr->parent = NULL;
return ptr;
}
VARSTORE *PeekVariableStoreContext(VARSTORE *varstore)
{
return FindTopmostContext(varstore);
}